use std::{fs, sync::Arc};

use arc_swap::ArcSwapOption;
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use shq_common::prelude::get_work_path;

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BigTableColumn {
    pub name: String,
    pub desc: String,
    #[serde(default = "dtid_col_default")]
    pub dtid_col_name: String,
    #[serde(default = "data_col_default")]
    pub data_col_name: String,
    pub df_tables: Vec<String>,
    #[serde(default)]
    pub mf_tables: Vec<String>,
    #[serde(default)]
    pub classify_types: Vec<ClassifyType>,
    #[serde(default)]
    pub classify_expr: ClassifyExpr,
    #[serde(default)]
    pub data_type: BaseDataType,
    pub where_cause: Option<String>,
}
fn dtid_col_default() -> String {
    "DTID".to_string()
}
fn data_col_default() -> String {
    "ACBL1".to_string()
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ClassifyExpr {
    Columns(Vec<String>),
    Exp(String),
    None
}
impl Default for ClassifyExpr {
    fn default() -> Self {
        ClassifyExpr::None
    }
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ClassifyType {
    TPNO,
    CYNO,
    ITID,
    PERD
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum BaseDataType {
    CompSave,
    CompLoan,
    CompBwyw,
    CompFana,
    IndiSave,
    IndiFana,
    IndiLoan,
    IndiClie,
    BankBiz,
    BizFee,
    CompMnlr,
    IndiMnlr,
    EconCap,
    None,
}
impl Default for BaseDataType {
    fn default() -> Self {
        BaseDataType::None
    }
}
impl BaseDataType {
    pub fn base_table_name(&self) -> &'static str {
        match self {
            BaseDataType::CompSave => "T_COMP_SAVE_BASE",
            BaseDataType::CompLoan => "T_COMP_LOAN_BASE",
            BaseDataType::CompFana => "T_COMP_FANA_BASE",
            BaseDataType::CompBwyw => "T_COMP_BWYW_BASE",
            BaseDataType::IndiSave => "T_INDI_ACCO_BASE",
            BaseDataType::IndiFana => "T_INDI_FANA_BASE",
            BaseDataType::IndiLoan => "T_INDI_LOAN_BASE",
            BaseDataType::IndiClie => "T_INDI_CLIE_ACBL_BASE",
            BaseDataType::BankBiz => "T_BANK_BIZ_BASE",
            BaseDataType::BizFee => "T_BIZ_FEES_BASE",
            BaseDataType::CompMnlr => "T_COMP_MNLR_BASE",
            BaseDataType::IndiMnlr => "T_INDI_MNLR_BASE",
            BaseDataType::EconCap => "T_ECON_CAP_BASE",
            BaseDataType::None => "",
        }
    }
}
static BIG_TABLE_CONFS: Lazy<ArcSwapOption<&'static Vec<BigTableColumn>>> =
    Lazy::new(|| ArcSwapOption::const_empty());

pub async fn init_big_table() -> anyhow::Result<()> {
    let file_path = format!("{}/config_files/big_table.yaml", get_work_path());
    let big_table_str = fs::read_to_string(file_path)?;
    let btcs: Vec<BigTableColumn> = serde_yaml::from_str(&big_table_str)
        .or_else(|err| Err(anyhow::anyhow!("解析配置文件big_table.yaml出错，错误信息{}", err)))?;
    let btcs_ref = Box::leak(Box::new(btcs));
    BIG_TABLE_CONFS.store(Some(Arc::new(btcs_ref)));
    Ok(())
}
pub fn get_big_table_column(name: &str) -> Option<&'static BigTableColumn> {
    let btcs = BIG_TABLE_CONFS.load();
    if let Some(btcs) = btcs.as_ref() {
        for btc in btcs.iter() {
            if btc.name == name {
                return Some(btc);
            }
        }
    }
    None
}
